#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include <unordered_map>

#include "TcpSocket.hpp"

#define MAX_WAIT_SIZE sizeof(fd_set)

class EpollSvr{
  public:
    EpollSvr(int size = 128){
      epoll_fd = epoll_create(size);
      svr_event.data.fd = -1;
      svr_event.events = EPOLLIN;
    }

    bool AddFd(int fd, struct sockaddr_in &addr){
      svr_event.data.fd = fd;
      int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &svr_event);
      if(ret < 0){
        perror("epoll_ctl");
        return false;
      }
      cli_addrs[fd] = addr;
      return true;
    }

    bool ModFd(int fd, epoll_event* event){
      int ret = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, event);
      if(ret < 0){
        perror("epoll_ctl");
        return false;
      }
      return true;
    }

    bool DelFd(int fd){
      int ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
      if(ret < 0){
        perror("epoll_ctl");
        return false;
      }
      return true;
    }

    int EpollWait(std::vector<std::pair<TcpSocket, sockaddr_in>> &re_events, int timeout = -1){
      struct epoll_event events[MAX_WAIT_SIZE];
      int ret = epoll_wait(epoll_fd, events, MAX_WAIT_SIZE - 1, timeout);
      re_events.resize(ret);
      for(int i = 0; i < ret; ++i){
        int fd = events[i].data.fd;
        re_events[i] = std::make_pair(TcpSocket(fd), cli_addrs[fd]);
      }
      return ret;
    }

    ~EpollSvr(){
      if(epoll_fd > 0){
        close(epoll_fd);
      }
    }
  private:
    int epoll_fd;
    struct epoll_event svr_event;
    std::unordered_map<int, sockaddr_in> cli_addrs;
};
